package com.hp.bon.sgw.wh.processor;

import static com.hp.bon.sgw.Constants.LOG;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.lang.StringEscapeUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hp.bon.sgw.Constants;
import com.hp.bon.sgw.Constants.ResultCode;
import com.hp.bon.sgw.bean.XmlMessage;
import com.hp.bon.sgw.core.BuzProcessorManager;
import com.hp.bon.sgw.core.CallParam;
import com.hp.bon.sgw.core.ChannelServer;
import com.hp.bon.sgw.core.InprogressMessageQueue;
import com.hp.bon.sgw.core.channel.handler.BaseWSCallHandler;
import com.hp.bon.sgw.core.processor.Processor;
import com.hp.bon.sgw.core.route.RouteInfo;
import com.hp.bon.sgw.util.Comutils;
import com.hp.bon.sgw.wh.service.BillDetailQueryConfigService;
import com.hp.ocs.diameter.message.AVP;
import com.hp.ocs.diameter.message.AVP_Grouped;
import com.hp.ocs.diameter.message.AVP_UTF8String;
import com.hp.ocs.diameter.message.AVP_Unsigned32;
import com.hp.ocs.diameter.message.InvalidAVPLengthException;
import com.hp.ocs.diameter.message.Message;

/** 
 * CopyRright (c)2016/12-:SGW_WH2.1_TMALL_20180102
 * Project:SGW_WH2.1_TMALL_20180102
 * Module ID:BillDetailQueryProcessor
 * Comments:TODO
 * @author :chenjun  
 * Create Date：2019年1月8日
 * Modified By：Chenjun                     
 * Modified Date:2019年1月8日
 * Why:TODO
 * Version:<v1.0> 
 */
public class BillDetailQueryProcessor extends Processor{

private static final Logger logger = LoggerFactory.getLogger(BillDetailQueryProcessor.class);
	
	private long time=1000L;
	
	private static HashMap<String, Integer> countMap = new HashMap<String, Integer>();
	
	private BillDetailQueryConfigService billDetailQueryConfigService ;
	
	
	public BillDetailQueryConfigService getBillDetailQueryConfigService() {
		return billDetailQueryConfigService;
	}

	public void setBillDetailQueryConfigService(
			BillDetailQueryConfigService billDetailQueryConfigService) {
		this.billDetailQueryConfigService = billDetailQueryConfigService;
	}

	public void shutdown() {
		dccProcessor.interrupt();
	}
	DccProcessor dccProcessor;
	public void init(){
		dccProcessor=new DccProcessor();
		dccProcessor.start();
	}
	
	class DccProcessor extends Thread{

		@Override
		public void run() {
			logger.info("-----rrrrrrrrrrrrrrr----");
			while (true) {
				try {
					time=billDetailQueryConfigService.getLongValue("limit_config_time", 1000L);
					//logger.info("time:"+time);
					countMap.clear();
					sleep(time);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
			}
		}
		
	}
	
	public  synchronized Integer putValue(String key) {
		Integer i =countMap.get(key);
		logger.info("asd:"+i);
		if (i==null) {
			countMap.put(key, 1);
			i = 1;
		}else{
			i++;
			countMap.put(key,i);
		}
		return i;
	}
	
	private CallParam sendReqMsg(CallParam callParam ,String data ,String sendCount ,String sci)	{
		logger.info("===========333333333333===============" );
		
		String sessionId2 = callParam.getSessionId();

		XmlMessage req = new XmlMessage(true);
		req.setDATA(data);
		try {
			req.setDataElement(Comutils.parseText(data).getRootElement());
		} catch (Exception e) {
			e.printStackTrace();
		}
		req.setMID(sessionId2);
		req.setUID(callParam.getUserName());
		req.setSCID(sci);
		CallParam newCallParam = new CallParam(sessionId2, sci, req, callParam.getUserName(), callParam.getAsynHandler());
		newCallParam.setBussinessCallId(callParam.getBussinessCallId());
		newCallParam.setRequest(req);
		newCallParam.setProcessor(this);
		logger.info("===========44444===========1===="+callParam.getServiceContextId());
		logger.info("===========333333333333===========1===="+newCallParam.getServiceContextId() );
		logger.info("===========333333333333=========2===="+sessionId2 );
		RouteInfo r = ChannelServer.findRoute(newCallParam.getServiceContextId());
		logger.info("===========333333333333r"+r);
		int ret = 0;
		String errMsg = null;
		if (r == null) {
			errMsg = "No Route for " + newCallParam.getServiceContextId();
			ret = 3002;// 没有查到路由
		} else if (r.result != 0) {
			errMsg = "Route unavailable for " + newCallParam.getServiceContextId();
			ret = r.result;
		}
		logger.info("===========ret===========1===="+ret );
		if (ret != 0) {
			newCallParam.setRetCode(3002);
			newCallParam.setResultMsg(errMsg);
			return newCallParam;
		}
		logger.info("============newCallParam=============="+ newCallParam.getResultMsg());
		newCallParam.setToNode(r.curNode);
		InprogressMessageQueue.getInstance().addRequest(newCallParam);
		r.curNode.getChannel().sendRequest(newCallParam);
		logger.info("============newCallParam=============="+ newCallParam.getResultMsg());
		logger.info("============newCallParam=============="+ newCallParam.getServiceResultCode());
		logger.info("============newCallParam=============="+ newCallParam.getRetCode());
		return newCallParam;
	}
	/**
	 * 
	 * @ 说     明：通过AVPCODE删除AVP，返回对应的删除索引位置	 
	 * @param：newMessage  Message
	 * @param：_AvpCode  int
	 * @return：返回对应的删除索引位置  0：无此AVP
	 */
	public static int removeAvpByAvpCode(Message newMessage,int _AvpCode){
		int _ind_removeAvp = -1;
		_ind_removeAvp  = newMessage.findFirst(_AvpCode);
		if( -1 != _ind_removeAvp){
			newMessage.remove(_ind_removeAvp);
		}
		return _ind_removeAvp;
	}
	
	@Override
	public int process(CallParam callParam) {
		logger.info("===========7777777777===============" );
		XmlMessage request = (XmlMessage) callParam.getRequest();
		AVP avp = null;
		String billingCycle="";
		String objId = "";
		long destinationAttr = -1;
		long queryFlag = -1;
		Document root;
		try {
			root = DocumentHelper.parseText(request.getDATA());
			org.dom4j.Node node = root.selectSingleNode("//Service_Information/Bill_Information/Acc_Nbr");
			if (node != null) {
				objId = node.getStringValue();
			}
			
			node = root.selectSingleNode("//Service_Information/Bill_Information/Billing_Cycle");
			if (node != null) {
				billingCycle = node.getStringValue();
				if(billingCycle.isEmpty()) {
					   Calendar cal = Calendar.getInstance();
					   int year = cal.get(Calendar.YEAR);
					   int month = cal.get(Calendar.MONTH )+1;
					   if(month < 10) {
						   billingCycle =year+"0"+month; 
					   }
					   else {
						   billingCycle = String.valueOf(year)+String.valueOf(month);
					   }
				}
				
			}
			int billingCycleInt = Integer.parseInt(billingCycle);
			node = root.selectSingleNode("//Service_Information/Bill_Information/Query_Flag");
			if (node != null) {
				queryFlag = Long.valueOf(node.getStringValue());
			}
			
			node = root.selectSingleNode("//Service_Information/Bill_Information/DestinationAttr");
			if (node != null) {
				destinationAttr = Long.valueOf(node.getStringValue());
			}
			StringBuilder buildStringMes = new StringBuilder();
			LOG.warn("start send ccr-----");
			String queryFlagStr = "\""+queryFlag+"\"";
			String destinationAttrStr = "\""+destinationAttr+"\"";
			String QueryFromStr = "\""+216+"\"";
			String objIdStr = "\""+objId+"\"";
			String billingCycleStr = "\""+billingCycle+"\"";
			int accountPeriod = Integer.parseInt(billDetailQueryConfigService.getValue("IS_ACCOUNT_PERIOD","201810"));
			if(billingCycleInt > accountPeriod) {
				LOG.warn("start webservice-----");
				buildStringMes.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ws=\"http://ws.hquery.ailk.com/\">");
				buildStringMes.append("<soapenv:Header/>");
				buildStringMes.append("<soapenv:Body>");
				buildStringMes.append("<ws:CustBillJTQry>");
				buildStringMes.append("<param>{\"ObjType\":\"0\",\"ObjId\":"+objIdStr+",\"QryFlag\":"+queryFlagStr+",\"BillMonth\":"+billingCycleStr+",\"DestinationAttr\":"+destinationAttrStr+",\"QueryFrom\":"+QueryFromStr+"}</param>");
				buildStringMes.append("</ws:CustBillJTQry>");
				buildStringMes.append("</soapenv:Body>");
				buildStringMes.append("</soapenv:Envelope>");
			    LOG.warn("buildStringMes------"+buildStringMes.toString());
			    String resp = StringEscapeUtils.unescapeXml(sendWebService(callParam, buildStringMes));
			    if(resp.equals("")) {
			    	callParam.setRetCode(1200);
			    	callParam.setResultMsg("time out");
			    	callParam.getAsynHandler().onCallResult(callParam);
			    }
			    else {
				    LOG.warn("resp------"+resp);
				    resp = resp.replaceAll("\r|\n", "");
			   		String  respStr = "<result>(.*)</result>";
			   		Pattern pattern = Pattern.compile(respStr);
			   		Matcher matcher = pattern.matcher(resp);
			   		String interceptRespStr = "";
			   		while (matcher.find()) {
			   			interceptRespStr = matcher.group(1);
			   		}
			   		JSONObject jsonObject = JSON.parseObject(interceptRespStr);
			   		StringBuilder sendCCAMsg = new StringBuilder();
			   		getWebServiceCCRMsg(jsonObject, sendCCAMsg);
			   		LOG.warn("sendCCAMsg------"+sendCCAMsg.toString());
			   		try {
						sendWebServiceCca(callParam, sendCCAMsg.toString());
					} catch (Exception e) {
						e.printStackTrace();
					}
			    }
			}
			else {
				LOG.warn("sendDCC------");
				buildStringMes.append("<Service_Information>");
				buildStringMes.append("<Bill_Information>");
				buildStringMes.append("<Acc_Nbr>"+objId+"</Acc_Nbr>");
				buildStringMes.append("<DestinationAttr>"+destinationAttr+"</DestinationAttr>");
				buildStringMes.append("<Billing_Cycle>"+billingCycle+"</Billing_Cycle>");
				buildStringMes.append("<Query_Flag>"+queryFlag+"</Query_Flag>");
				buildStringMes.append("</Bill_Information>");
				buildStringMes.append("</Service_Information>");
				LOG.warn("buildStringMesDCC------"+buildStringMes.toString());
				CallParam callParam2 = this.sendReqMsg(callParam, buildStringMes.toString(), "2", "BillDetailQuery.BillYXHB9@027.ctnbc-bon.net");
				LOG.warn("callParam2-----"+callParam2.getRetCode());
				if(callParam2.getRetCode() == 3002) {
					callParam2.setRetCode(11202);
					callParam2.setRequest(callParam.getRequest());
					callParam2.getAsynHandler().onCallResult(callParam2);
					return 0;
				}
				
			}
			
		} catch (DocumentException e1) {
			e1.printStackTrace();
		}
		
		return 0;
	}

	private void sendWebServiceCca(CallParam callParam, String resp)
			throws Exception
	{
		LOG.warn("sendwebservicecca------");
		LOG.warn("respStr------"+resp);
		XmlMessage ack = new XmlMessage(false);
		if(!resp.isEmpty()) {
			XmlMessage message = (XmlMessage)callParam.getRequest();
			String mid = message.getMID();
			Document docResp = Comutils.parseText(resp);
			ack.setDataElement(docResp.getRootElement());
			ack.setMID(mid.substring(0, mid.length()-1));
			ack.setREPTAG(0);
			ack.setRTT(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(Long.valueOf(System.currentTimeMillis())));
			ack.setSIG(null);
			ack.setRC("0");
			ack.setDS("SUCCESS");
			ack.setDATA(resp);
			callParam.setRetCode(0);
			callParam.setRecvResponse(ack);
		}
		callParam.getAsynHandler().onCallResult(callParam);
	}

	private void getWebServiceCCRMsg(JSONObject jsonObject, StringBuilder sendCCAMsg) {
		sendCCAMsg.append("<Service_Information>");
		String resultCode = (String)jsonObject.get("Service_Result_Code");
		if(!resultCode.equals("0")) {
			sendCCAMsg.append("<Service_Result_Code>"+jsonObject.get("Service_Result_Code")+"</Service_Result_Code>");
			String fieldResult = (String)jsonObject.get("Para_Field_Result");
			if(!fieldResult.isEmpty()) {
				sendCCAMsg.append("<Para_Field_Result>"+jsonObject.get("Para_Field_Result")+"</Para_Field_Result>");
			}
			sendCCAMsg.append("</Service_Information>");
		}
		else {
			sendCCAMsg.append("<Result>"+jsonObject.get("Service_Result_Code")+"</Result>");
			sendCCAMsg.append("<Para_Field_Result>"+jsonObject.get("Para_Field_Result")+"</Para_Field_Result>");
			if(jsonObject.getJSONObject("Bill_Information")!=null) {
				sendCCAMsg.append("<Bill_Information>");
				sendCCAMsg.append("<Acct_Name>"+jsonObject.getJSONObject("Bill_Information").get("Acct_Name")+"</Acct_Name>");
				sendCCAMsg.append("<Total_Charge>"+jsonObject.getJSONObject("Bill_Information").get("Sum_Charge")+"</Total_Charge>");
				sendCCAMsg.append("<Charge_Payed>"+jsonObject.getJSONObject("Bill_Information").get("ChargePayed")+"</Charge_Payed>");
				sendCCAMsg.append("<ChargeShouldPayed>"+jsonObject.getJSONObject("Bill_Information").get("ChargeShouldPayed")+"</ChargeShouldPayed>");
				sendCCAMsg.append("<ChargeFreeDiscount>"+jsonObject.getJSONObject("Bill_Information").get("ChargeFreeDiscount")+"</ChargeFreeDiscount>");
				sendCCAMsg.append("<ChargeCorpusDiscount>"+jsonObject.getJSONObject("Bill_Information").get("ChargeCorpusDiscount")+"</ChargeCorpusDiscount>");
				sendCCAMsg.append("<AccNbrDetail>"+jsonObject.getJSONObject("Bill_Information").get("AccNbrDetail")+"</AccNbrDetail>");
				JSONArray family =jsonObject.getJSONObject("Bill_Information").getJSONArray("Item_Information");
				//family.getJSONObject(index)
				for (int i = 0; i < family.size(); i++){
					JSONObject s1 = family.getJSONObject(i);
					sendCCAMsg.append("<Item_Information>");
					sendCCAMsg.append("<Show_level>"+s1.get("Show_level")+"</Show_level>");
					String chargeTypeName = (String)s1.get("Charge_type_Name");
					chargeTypeName = chargeTypeName.replaceAll("&", "");
					sendCCAMsg.append("<Charge_type_Name>"+chargeTypeName+"</Charge_type_Name>");
					sendCCAMsg.append("<Charge>"+s1.get("Charge")+"</Charge>");
					sendCCAMsg.append("<Class_Id>"+s1.get("Class_Id")+"</Class_Id>");
					sendCCAMsg.append("<Parent_Class_Id>"+s1.get("Parent_Class_Id")+"</Parent_Class_Id>");
					String productOFFName = (String)s1.get("Product_OFF_Name");
					logger.info("===========productOFFName==============="+productOFFName);
					if(productOFFName.isEmpty()) {
						productOFFName = " ";
					}
					sendCCAMsg.append("<Product_OFF_Name>"+productOFFName+"</Product_OFF_Name>");
					sendCCAMsg.append("<AccNbrDetail>"+s1.get("AccNbrDetail")+"</AccNbrDetail>");
					sendCCAMsg.append("</Item_Information>");
					
				}
				sendCCAMsg.append("</Bill_Information>");
			}
			sendCCAMsg.append("</Service_Information>");
		}
	}
	
	private String sendWebService(CallParam callParam, StringBuilder sb) {
		String url  = billDetailQueryConfigService.getValue("RATABLE_RESOURCE_QUERY_URL","");
		logger.info("===========webservice url==============="+url);
		String resp = "";
		logger.info("===========webservice url==============="+url);
		PostMethod post = new PostMethod(url);
		try {
			RequestEntity requestEntity = new StringRequestEntity(sb.toString(), "text/xml", "UTF-8");
			post.setRequestEntity(requestEntity);
			HttpClient client = new HttpClient();
			int timeOut = Integer.parseInt(billDetailQueryConfigService.getValue("IS_WEBSERVICE_REQUEST_TIMEOUT","5000"));
			client.getHttpConnectionManager().getParams().setConnectionTimeout(5*1000);
			client.getHttpConnectionManager().getParams().setSoTimeout(timeOut);
			try {
				client.executeMethod(post);
			} catch (HttpException e) {
				logger.info("===========webservice call timeout==============="+url);
				e.printStackTrace();
			} catch (IOException e) {
				logger.info("===========webservice call timeout session_id:"+callParam.getSessionId());
				return "";
			}
			try {
				logger.info("===========完成webservice==============="+resp);
				resp = post.getResponseBodyAsString();
			} catch (IOException e) {
				logger.info("===========webservice call timeout==============="+url);
				return "";
			}
		} catch (UnsupportedEncodingException e) {
			logger.info("===========webservice call timeout==============="+url);
			e.printStackTrace();
		}
		return resp;
	}

	public CallParam parseResponse(CallParam callParam) {
		Message request = (Message) callParam.getRecvResponse();
		Message answer = new Message();
		answer.prepareResponse(request);
		String sessionId = callParam.getSessionId();
		sessionId = sessionId.substring(0,sessionId.length()-2);
		request.updateAVP_UTF8String("263", sessionId);
		CallParam newcallParam = changeAVPTOXMl(callParam, request, sessionId);
		return newcallParam;
	}
	public int endProcess(CallParam callParam) {
		logger.info("callParam.getServiceResultCode()----"+callParam.getServiceResultCode());
		if(callParam.getServiceResultCode() == -1) {
			callParam.getAsynHandler().onCallResult(callParam);
		}
		else {
			callParam.getAsynHandler().onCallResult(parseResponse(callParam));
		}
		return 0;
	}
	
	private CallParam changeAVPTOXMl(CallParam callParam, Message request,String sessionId) {
		CallParam newcallParam = new CallParam(sessionId, callParam.getServiceContextId(), request, callParam.getUserName(), callParam.getAsynHandler());
		XmlMessage ack = new XmlMessage(false);
		XmlMessage message = (XmlMessage)callParam.getRequest();
		Message messageRequset = (Message)newcallParam.getRequest();
		ack.setMID(message.getMID());
		ack.setREPTAG(0);
		ack.setSIG(null);
		ack.setRC("0");
		ack.setDS("SUCCESS");
		ack.setDATA(request.getDictionary().toString());
		newcallParam.setRecvResponse(callParam.getRecvResponse());
		newcallParam.setRequest(callParam.getRequest());
		ack = BuzProcessorManager.getInstance().convertMessageToAck(newcallParam);
		newcallParam.setRequest(messageRequset);
		newcallParam.setFromNode(callParam.getFromNode());
		newcallParam.setRecvResponse(ack);
		newcallParam.setResponse(null);
		return newcallParam;
	}


}
